<?php
require_once __DIR__ . '/config/database.php';
require_once __DIR__ . '/includes/functions.php';

// 简单的WebSocket服务器实现（不依赖外部库）
class SimpleWebSocketServer {
    private $socket;
    private $clients = array();
    private $host;
    private $port;
    
    public function __construct($host = 'localhost', $port = 8080) {
        $this->host = $host;
        $this->port = $port;
    }
    
    // 尝试不同端口的方法
    private function findAvailablePort($startPort = 8080) {
        for ($port = $startPort; $port <= $startPort + 10; $port++) {
            $testSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            socket_set_option($testSocket, SOL_SOCKET, SO_REUSEADDR, 1);
            
            if (socket_bind($testSocket, $this->host, $port)) {
                socket_close($testSocket);
                return $port;
            }
            socket_close($testSocket);
        }
        return false;
    }
    
    // 保存端口配置
    private function savePortConfig() {
        $config = [
            'host' => $this->host,
            'port' => $this->port,
            'updated_at' => date('Y-m-d H:i:s')
        ];
        file_put_contents(__DIR__ . '/websocket_config.json', json_encode($config));
    }
    
    public function start() {
        echo "正在创建WebSocket服务器...\n";
        echo "Host: {$this->host}\n";
        echo "Port: {$this->port}\n";
        
        // 创建socket
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if (!$this->socket) {
            $error = socket_strerror(socket_last_error());
            echo "错误: socket_create() 失败: {$error}\n";
            die("socket_create() failed: " . $error);
        }
        echo "Socket创建成功\n";
        
        // 设置socket选项
        echo "设置Socket选项...\n";
        if (!socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
            $error = socket_strerror(socket_last_error($this->socket));
            echo "警告: 设置SO_REUSEADDR失败: {$error}\n";
        }
        
        // 尝试绑定原端口，如果失败则寻找可用端口
        echo "尝试绑定到 {$this->host}:{$this->port}...\n";
        if (!socket_bind($this->socket, $this->host, $this->port)) {
            $error = socket_strerror(socket_last_error($this->socket));
            echo "端口 {$this->port} 绑定失败: {$error}\n";
            echo "正在寻找可用端口...\n";
            
            $availablePort = $this->findAvailablePort($this->port);
            if ($availablePort === false) {
                die("无法找到可用端口，请检查系统配置\n");
            }
            
            // 关闭当前socket，使用新端口重新创建
            socket_close($this->socket);
            $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
            
            $this->port = $availablePort;
            echo "使用端口: {$this->port}\n";
            
            if (!socket_bind($this->socket, $this->host, $this->port)) {
                die("socket_bind() failed: " . socket_strerror(socket_last_error($this->socket)));
            }
        }
        
        // 开始监听
        echo "开始监听连接...\n";
        if (!socket_listen($this->socket, 100)) {
            $error = socket_strerror(socket_last_error($this->socket));
            echo "错误: socket_listen() 失败: {$error}\n";
            die("socket_listen() failed: " . $error);
        }
        
        echo "✓ WebSocket服务器成功启动!\n";
        echo "✓ 监听地址: {$this->host}:{$this->port}\n";
        echo "✓ 监听队列长度: 100\n";
        echo "✓ 连接限制: 每个IP+设备组合只能连接一个WebSocket\n";
        echo "✓ 设备识别: 自动识别移动端/桌面端/平板设备\n";
        echo "✓ 服务器状态: 运行中\n";
        echo "按 Ctrl+C 停止服务器\n";
        echo "================================\n\n";
        
        // 将端口信息写入配置文件供前端使用
        $this->savePortConfig();
        echo "✓ 配置文件已更新: websocket_config.json\n\n";
        
        // 主循环
        while (true) {
            $read = array($this->socket);
            foreach ($this->clients as $client) {
                $read[] = $client['socket'];
            }
            
            $write = null;
            $except = null;
            
            if (socket_select($read, $write, $except, 1) > 0) {
                // 检查新连接
                if (in_array($this->socket, $read)) {
                    $newSocket = socket_accept($this->socket);
                    if ($newSocket) {
                        $this->handleNewConnection($newSocket);
                    }
                    $key = array_search($this->socket, $read);
                    unset($read[$key]);
                }
                
                // 处理客户端消息
                foreach ($read as $clientSocket) {
                    $this->handleClientMessage($clientSocket);
                }
            }
            
            // 定期发送价格更新
            $this->sendPriceUpdate();
            
            // 每30秒显示连接统计信息
            static $lastStats = 0;
            if (time() - $lastStats >= 30) {
                $this->showConnectionStats();
                $lastStats = time();
            }
            
            // 短暂休眠以避免CPU占用过高
            usleep(100000); // 0.1秒
        }
    }
    
    private function handleNewConnection($socket) {
        // 获取客户端IP地址
        $clientIP = $this->getClientIP($socket);
        
        // 获取客户端设备信息（从HTTP请求头中）
        $request = socket_read($socket, 2048);
        if (!$request) {
            socket_close($socket);
            return;
        }
        
        // 解析请求头获取设备信息
        $deviceInfo = $this->parseDeviceInfo($request);
        $deviceId = $this->generateDeviceId($clientIP, $deviceInfo);
        
        // 检查该IP+设备组合是否已经有连接
        if ($this->isDeviceAlreadyConnected($clientIP, $deviceId)) {
            echo "拒绝连接: IP {$clientIP} 设备 {$deviceId} 已有连接\n";
            socket_close($socket);
            return;
        }
        
        // 执行WebSocket握手
        $response = $this->doHandshake($request);
        socket_write($socket, $response, strlen($response));
        
        $clientId = uniqid();
        $this->clients[$clientId] = array(
            'socket' => $socket,
            'handshake' => true,
            'connected_at' => time(),
            'ip' => $clientIP,
            'device_id' => $deviceId,
            'user_agent' => $deviceInfo['user_agent'] ?? '未知',
            'device_type' => $deviceInfo['device_type'] ?? '未知'
        );
        
        echo "新客户端连接: {$clientId} (IP: {$clientIP}, 设备: {$deviceId})\n";
        
        // 立即发送当前价格
        $this->sendPriceUpdateToClient($clientId);
    }
    
    // 获取客户端IP地址
    private function getClientIP($socket) {
        socket_getpeername($socket, $clientIP);
        return $clientIP;
    }
    
    // 解析HTTP请求头获取设备信息
    private function parseDeviceInfo($request) {
        $headers = array();
        $lines = preg_split("/\r\n/", $request);
        
        foreach($lines as $line) {
            $line = trim($line);
            if(preg_match('/^([^:]+):\s*(.+)$/', $line, $matches)) {
                $headerName = strtolower(trim($matches[1]));
                $headerValue = trim($matches[2]);
                $headers[$headerName] = $headerValue;
            }
        }
        
        $userAgent = $headers['user-agent'] ?? '';
        $deviceType = $this->detectDeviceType($userAgent);
        
        return array(
            'user_agent' => $userAgent,
            'device_type' => $deviceType
        );
    }
    
    // 检测设备类型
    private function detectDeviceType($userAgent) {
        $userAgent = strtolower($userAgent);
        
        if (strpos($userAgent, 'mobile') !== false || strpos($userAgent, 'android') !== false || strpos($userAgent, 'iphone') !== false) {
            return 'mobile';
        } elseif (strpos($userAgent, 'tablet') !== false || strpos($userAgent, 'ipad') !== false) {
            return 'tablet';
        } elseif (strpos($userAgent, 'windows') !== false || strpos($userAgent, 'macintosh') !== false || strpos($userAgent, 'linux') !== false) {
            return 'desktop';
        } else {
            return 'unknown';
        }
    }
    
    // 生成设备ID（基于IP和设备特征）
    private function generateDeviceId($clientIP, $deviceInfo) {
        $deviceString = $clientIP . '|' . $deviceInfo['device_type'] . '|' . substr(md5($deviceInfo['user_agent']), 0, 8);
        return md5($deviceString);
    }
    
    // 检查IP+设备组合是否已经有连接
    private function isDeviceAlreadyConnected($clientIP, $deviceId) {
        foreach ($this->clients as $client) {
            if (isset($client['ip']) && $client['ip'] === $clientIP && 
                isset($client['device_id']) && $client['device_id'] === $deviceId) {
                return true;
            }
        }
        return false;
    }
    
    // 显示连接统计信息
    private function showConnectionStats() {
        $totalConnections = count($this->clients);
        $uniqueIPs = array();
        $deviceTypes = array();
        
        foreach ($this->clients as $client) {
            if (isset($client['ip'])) {
                $uniqueIPs[] = $client['ip'];
            }
            if (isset($client['device_type'])) {
                $deviceTypes[] = $client['device_type'];
            }
        }
        
        $uniqueIPs = array_unique($uniqueIPs);
        $uniqueIPCount = count($uniqueIPs);
        $deviceTypeCounts = array_count_values($deviceTypes);
        
        echo "📊 连接统计: 总连接数: {$totalConnections}, 唯一IP数: {$uniqueIPCount}\n";
        
        if (!empty($deviceTypeCounts)) {
            echo "📱 设备类型: ";
            $deviceInfo = array();
            foreach ($deviceTypeCounts as $type => $count) {
                $deviceInfo[] = "{$type}: {$count}";
            }
            echo implode(', ', $deviceInfo) . "\n";
        }
        
        if (!empty($uniqueIPs)) {
            echo "📍 已连接IP: " . implode(', ', $uniqueIPs) . "\n";
        }
        echo "---\n";
    }
    
    private function doHandshake($request) {
        $headers = array();
        $lines = preg_split("/\r\n/", $request);
        foreach($lines as $line) {
            $line = chop($line);
            if(preg_match('/\A(\S+): (.*)\z/', $line, $matches)) {
                $headers[$matches[1]] = $matches[2];
            }
        }
        
        $secKey = $headers['Sec-WebSocket-Key'];
        $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
        
        $response = "HTTP/1.1 101 Switching Protocols\r\n" .
                   "Upgrade: websocket\r\n" .
                   "Connection: Upgrade\r\n" .
                   "Sec-WebSocket-Accept: {$secAccept}\r\n\r\n";
        
        return $response;
    }
    
    private function handleClientMessage($socket) {
        $data = socket_read($socket, 2048);
        if ($data === false) {
            // 连接断开
            $this->removeClient($socket);
        } else if ($data) {
            $decoded = $this->decode($data);
            if ($decoded) {
                echo "收到消息: " . $decoded . "\n";
                // 可以根据消息内容进行不同处理
            }
        }
    }
    
    private function removeClient($socket) {
        foreach ($this->clients as $clientId => $client) {
            if ($client['socket'] === $socket) {
                $clientIP = isset($client['ip']) ? $client['ip'] : '未知';
                $deviceType = isset($client['device_type']) ? $client['device_type'] : '未知';
                socket_close($socket);
                unset($this->clients[$clientId]);
                echo "客户端断开连接: {$clientId} (IP: {$clientIP}, 设备: {$deviceType})\n";
                break;
            }
        }
    }
    
    private function sendPriceUpdate() {
        static $lastUpdate = 0;
        static $lastRoundStatus = '';
        static $lastRoundNumber = 0;
        $now = time();
        
        // 每3秒发送一次价格更新
        if ($now - $lastUpdate >= 3) {
            $lastUpdate = $now;
            
            try {
                // 更新游戏状态
                updateGameState();
                
                // 获取最新价格和游戏信息
                $currentPrice = getCurrentPrice();
                $currentRound = getCurrentRound();
                
                // 获取价格历史数据
                $priceHistory = getPriceHistory(30);
                
                // 检查轮次状态是否发生变化
                $roundStatusChanged = ($lastRoundStatus !== $currentRound['status'] || $lastRoundNumber !== $currentRound['round_number']);
                
                if ($roundStatusChanged) {
                    // 发送轮次状态更新
                    $roundData = array(
                        'type' => 'round_update',
                        'round_info' => array(
                            'round_number' => $currentRound['round_number'],
                            'status' => $currentRound['status'],
                            'start_time' => $currentRound['start_time'],
                            'end_time' => $currentRound['end_time'],
                            'settlement_price' => $currentRound['settlement_price']
                        ),
                        'timestamp' => date('Y-m-d H:i:s')
                    );
                    
                    $this->broadcastMessage($roundData);
                    
                    // 更新状态记录
                    $lastRoundStatus = $currentRound['status'];
                    $lastRoundNumber = $currentRound['round_number'];
                    
                    echo "轮次状态更新: 第{$currentRound['round_number']}轮 - {$currentRound['status']}\n";
                }
                
                // 发送价格更新
                $data = array(
                    'type' => 'price_update',
                    'current_price' => $currentPrice,
                    'price_history' => $priceHistory,
                    'round' => $currentRound['round_number'],
                    'status' => $currentRound['status'],
                    'timestamp' => date('Y-m-d H:i:s')
                );
                
                $this->broadcastMessage($data);
                
                // 检查是否有新交易记录需要推送
                $this->checkAndSendNewTransactions($currentRound['id']);
                
            } catch (Exception $e) {
                echo "价格更新失败: " . $e->getMessage() . "\n";
            }
        }
    }
    
    // 检查并发送新交易记录
    private function checkAndSendNewTransactions($roundId) {
        static $lastTransactionId = 0;
        
        try {
            global $pdo; // 使用全局数据库连接
            
            // 获取最新交易记录
            $stmt = $pdo->prepare("
                SELECT 
                    t.id,
                    t.user_id,
                    u.username,
                    t.type,
                    t.quantity,
                    t.price,
                    t.amount,
                    t.profit,
                    t.fee,
                    t.transaction_time
                FROM 
                    transactions t
                JOIN 
                    users u ON t.user_id = u.id
                WHERE 
                    t.round_id = ? AND t.id > ?
                ORDER BY 
                    t.transaction_time DESC
                LIMIT 5
            ");
            
            $stmt->execute([$roundId, $lastTransactionId]);
            $newTransactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            if (!empty($newTransactions)) {
                // 更新最后处理的交易ID
                $lastTransactionId = max(array_column($newTransactions, 'id'));
                
                // 处理交易记录，保护用户隐私
                foreach ($newTransactions as &$transaction) {
                    $username = $transaction['username'];
                    $length = mb_strlen($username, 'UTF-8');
                    
                    if ($length > 4) {
                        $transaction['username'] = mb_substr($username, 0, 1, 'UTF-8') . '***' . mb_substr($username, -1, 1, 'UTF-8');
                    } else if ($length > 2) {
                        $transaction['username'] = mb_substr($username, 0, 1, 'UTF-8') . '**';
                    } else {
                        $transaction['username'] = $username[0] . '*';
                    }
                    
                    // 转换时间格式
                    $transaction['transaction_time'] = date('H:i:s', strtotime($transaction['transaction_time']));
                    
                    // 格式化数值
                    $transaction['quantity'] = floatval($transaction['quantity']);
                    $transaction['price'] = floatval($transaction['price']);
                    $transaction['amount'] = floatval($transaction['amount']);
                    $transaction['profit'] = floatval($transaction['profit']);
                    $transaction['fee'] = floatval($transaction['fee']);
                }
                
                // 推送新交易记录
                $data = array(
                    'type' => 'new_transactions',
                    'transactions' => $newTransactions,
                    'timestamp' => date('Y-m-d H:i:s')
                );
                
                $this->broadcastMessage($data);
                echo "推送新交易记录: " . count($newTransactions) . " 条\n";
            }
            
        } catch (Exception $e) {
            echo "检查新交易记录失败: " . $e->getMessage() . "\n";
        }
    }
    
    private function sendPriceUpdateToClient($clientId) {
        try {
            $currentPrice = getCurrentPrice();
            $currentRound = getCurrentRound();
            
                            // 获取价格历史数据
                $priceHistory = getPriceHistory(30);
                
                $data = array(
                    'type' => 'price_update',
                    'current_price' => $currentPrice,
                    'price_history' => $priceHistory,
                    'round' => $currentRound['status'],
                    'round_number' => $currentRound['round_number'],
                    'timestamp' => date('Y-m-d H:i:s')
                );
            
            $this->sendToClient($clientId, $data);
        } catch (Exception $e) {
            echo "发送价格给客户端失败: " . $e->getMessage() . "\n";
        }
    }
    
    private function broadcastMessage($data) {
        $message = json_encode($data);
        $encodedMessage = $this->encode($message);
        
        foreach ($this->clients as $clientId => $client) {
            if ($client['handshake']) {
                $result = socket_write($client['socket'], $encodedMessage, strlen($encodedMessage));
                if ($result === false) {
                    $this->removeClient($client['socket']);
                }
            }
        }
    }
    
    private function sendToClient($clientId, $data) {
        if (isset($this->clients[$clientId]) && $this->clients[$clientId]['handshake']) {
            $message = json_encode($data);
            $encodedMessage = $this->encode($message);
            
            $result = socket_write($this->clients[$clientId]['socket'], $encodedMessage, strlen($encodedMessage));
            if ($result === false) {
                $this->removeClient($this->clients[$clientId]['socket']);
            }
        }
    }
    
    private function encode($message) {
        $length = strlen($message);
        
        if ($length < 126) {
            return chr(129) . chr($length) . $message;
        } elseif ($length < 65536) {
            return chr(129) . chr(126) . pack("n", $length) . $message;
        } else {
            return chr(129) . chr(127) . pack("NN", 0, $length) . $message;
        }
    }
    
    private function decode($data) {
        $length = ord($data[1]) & 127;
        
        if ($length == 126) {
            $masks = substr($data, 4, 4);
            $data = substr($data, 8);
        } elseif ($length == 127) {
            $masks = substr($data, 10, 4);
            $data = substr($data, 14);
        } else {
            $masks = substr($data, 2, 4);
            $data = substr($data, 6);
        }
        
        $text = '';
        for ($i = 0; $i < strlen($data); ++$i) {
            $text .= $data[$i] ^ $masks[$i % 4];
        }
        
        return $text;
    }
}

// 启动WebSocket服务器
// 修改第322行，使用正确的IP地址
$server = new SimpleWebSocketServer('0.0.0.0', 8080); // 监听所有网络接口
$server->start();
?>
